<?php
date_default_timezone_set('Asia/Shanghai');
mb_internal_encoding("UTF-8");

class update
{
    private $ini = [
        'gitBash' => 'git', //git命令行脚本的位置, 需要将git/bin路径加入环境变量
        'cacheDir' => './cache', //拉取git时存放的目录
        'targetDir'=> '..', //拉取git后, 把代码复制到的目录前缀
        'projects' => [
            'SummerPHP' =>[
                'gitRepo' => 'https://gitee.com/myDcool/SummerPHP.git',
                'targetDir' => '',
                'needFiles' => [
                    'core',
                    'libs',
                    'model/User.php',
                    'modules/cli/queue.php',
                    'modules/index/BaseIndex.php',
                    'modules/user/login.php',
                    'modules/user/logout.php',
                    'modules/user/register.php',
                    'static/sys/css',
                    'static/sys/icons',
                    'static/sys/js',
                    'tool/script',
                    'tool/sqls',
                    'view/user',
                    'cli.php',
                    'index.php']
            ]
        ]
    ];
    
    private $output = [];
    private $logFile = './cache/update.log';
    
    public function __construct()
    {
        $gitBin = $this->ini['gitBash'];
    
        $this->imkdir($this->ini['targetDir']);
        $targetDir = realpath($this->ini['targetDir']);
        $targetDir = rtrim($targetDir, '/').'/';
    
        $this->imkdir($this->ini['cacheDir']);
        $cacheDir = realpath($this->ini['cacheDir']);
        $cacheDir = rtrim($cacheDir, '/').'/';
    
        foreach ($this->ini['projects'] as $pname=> $info) {
            $cacheGitRepoDir = $cacheDir.$pname;
            if (!file_exists($cacheGitRepoDir)) {
                $this->imkdir($cacheGitRepoDir);
                $cmd = "{$gitBin} clone {$info['gitRepo']} {$cacheGitRepoDir}";
                $this->output[] = '项目不存在, git clone ...';
                $this->iexec($cmd);
            }
    
            $cmd = "cd {$cacheGitRepoDir} && {$gitBin} checkout master && {$gitBin} pull";
            $this->output[] = '更新代码 ...';
            $this->iexec($cmd);
    
            $cmd = "cd {$cacheGitRepoDir} && {$gitBin} tag";
            $this->output[] = '拉取所有tag...';
            $arr = $this->iexec($cmd);
            $tagName = array_pop($arr);
            
            $cmd = "cd {$cacheGitRepoDir} && {$gitBin} checkout {$tagName}";
            $this->output[] = '切换到最新tag: '. $tagName;
            $this->iexec($cmd);
        }
    
        foreach ($this->ini['projects'] as $pname=> $info) {
            foreach ($info['needFiles'] as $file) {
                $sourceFilePath = $cacheDir.$pname.'/'.$file;
                $targetFilePath = $targetDir.$file;
            
                if (file_exists($sourceFilePath)) {
                    $this->icopy($sourceFilePath, $targetFilePath);
                } else {
                    $this->output[] = '文件不存在 '.$sourceFilePath;
                }
            }
        }
    }
    
    private function isWin()
    {
        if (strpos(PHP_OS, 'WIN') !== FALSE) {
            return TRUE;
        } else {
            return FALSE;
        }
    }
    
    private function imkdir($dir)
    {
        if (file_exists($dir)) {
            return;
        }
        
        if ($this->isWin()) {
            $cmd = escapeshellcmd('md "'.$dir.'"');
            $this->iexec($cmd);
            
        } else {
            //$cmd = escapeshellcmd('mkdir "'.$dir.'"');
        }
    }
    
    private function icopy($sourceFile, $targetDir)
    {
        if (strpos($targetDir, '.') !== FALSE) {
            $targetDir = dirname($targetDir);
        }
        $this->imkdir($targetDir);
        
        $source = realpath($sourceFile);
        $target = realpath($targetDir);
        
        if ($this->isWin()) {
            $cmd = escapeshellcmd('copy /y "'.$source.'" "'.$target.'"');
            $this->iexec($cmd);
            
        } else {
        
        }
    }
    
    public function iexec($cmd, $cwd='')
    {
        $descriptorspec = array(
            //0 => array("pipe", "r"),  // 标准输入，子进程从此管道中读取数据
            1 => array("pipe", "w"),  // 标准输出，子进程向此管道中写入数据
            2 => array("file", $this->logFile, "a") // 标准错误，写入到一个文件
        );
    
        //$cmd = 'gti pull';
        $cwd = empty($cwd) ? '.' : $cwd; //设置执行命令的目录
        $options = array('bypass_shell ' => true);
    
        $process = proc_open($cmd, $descriptorspec, $pipes, $cwd, null, $options);
        
        $this->output[] = $cmd;
    
        if (is_resource($process)) {
            // $pipes 现在看起来是这样的：
            // 0 => 可以向子进程标准输入写入的句柄
            // 1 => 可以从子进程标准输出读取的句柄
            // 错误输出将被追加到文件 /tmp/error-output.txt
        
            // fwrite($pipes[0]);
            // fclose($pipes[0]);
        
            //获取输出
            $this->output[] = $output = stream_get_contents($pipes[1]);
            fclose($pipes[1]);
            
            $str = preg_replace('#[\r\n|\n|\r]#', '@@', $output);
            $arr = explode('@@',$str);
            $arr = array_filter($arr);
        
            // 切记：在调用 proc_close 之前关闭所有的管道以避免死锁。
            $return_value = proc_close($process);
            //echo "command returned $return_value\n";
            
            return $arr;
        }
    }
    
    public function log()
    {
        file_put_contents($this->logFile, PHP_EOL.date('Y-m-d H:i:s').PHP_EOL.implode(PHP_EOL, $this->output), FILE_APPEND);
    }
    
}

$obj = new update();
$obj->log();
echo 'over!';